#include "simple_library/public/simple_library.h"
#include "simple_library/public/simple_library_macro.h"

#define VARIABLE(...)

namespace soft_rasterization
{
	class SIMPLE_LIBRARY_API fobject
	{
		friend class fengine;
	public:
		fobject();

	public:
		virtual void build(float in_time) {}
		virtual void tick(float in_time) {}
		virtual void clear() {}

	public:
		template<class t>
		t *create_object()
		{
			gobject_array.push_back(new t());

			return dynamic_cast<t*>(gobject_array[gobject_array.size() - 1]);
		}

	private:
		static void gobject_array_init(float in_time);
		static void gobject_array_tick(float in_time);
		static void gobject_array_clear();

	private:
		static std::vector<fobject*> gobject_array;
	};

	class SIMPLE_LIBRARY_API fcomponent : public fobject
	{
	public:
		fcomponent* parent;
		std::vector<fcomponent*> children;
	};

	class SIMPLE_LIBRARY_API ftransform_component :public fcomponent
	{
	public:
		ftransform_component();

		virtual void build(float in_time) {}
		virtual void tick(float in_time);
		virtual void clear() {}

	public:
		virtual void set_rot(const frotator &in_rot);

		virtual frotator get_rot() const { return rotation; }

	public:
		fvector_3d position;
		frotator rotation;
		fvector_3d scale;

		fvector_3d forward_vector;
		fvector_3d right_vector;
		fvector_3d up_vector;

		fmatrix_4x4 matrix;
		fmatrix_4x4 viewProj_matrix;

	protected:
		frotator last_rotation;
	};

	class SIMPLE_LIBRARY_API fmesh_component :public ftransform_component
	{
	public:
		std::vector<fvector_3d> vertex_data;
	};

	class SIMPLE_LIBRARY_API factor :public fobject
	{
		VARIABLE(category = actor, visibleanywhere, blueprintreadonly, meta = (allowprivateaccess = "true"))
		ftransform_component* transform; 

	public:
		factor();
		virtual ~factor();

		virtual void set_rot(const frotator& in_rot);
		virtual frotator get_rot() const {return transform->get_rot();}

		FORCEINLINE ftransform_component* get_transform() { return transform; }
	};

	class SIMPLE_LIBRARY_API fcamera :public factor
	{
	public:
	};

	class fmesh_actor :public factor
	{
		VARIABLE(category = actor, visibleanywhere, blueprintreadonly, meta = (allowprivateaccess = "true"))
		fmesh_component* mesh_component;

	public:
		fmesh_actor();
		~fmesh_actor();

		FORCEINLINE fmesh_component* get_mesh() { return mesh_component; }
	};

	struct SIMPLE_LIBRARY_API fviewport_config
	{
		fviewport_config()
			:viewport_size(1920, 1080)
			, fov(0.5f * 3.1415926f)
			, aspect_ratio(viewport_size.x / viewport_size.y)
			, near_z(1.f)
			, far_z(1000.f)
		{
		}

		fvector_2d viewport_size;

		float fov;
		float aspect_ratio;
		float near_z;
		float far_z;
	};
	struct SIMPLE_LIBRARY_API frender_data_3d
	{
		std::vector<fvector_3d> vertex_data;
		std::vector<uint16_t> index_data;

		fmatrix_4x4 matrix;
	};

	struct SIMPLE_LIBRARY_API frender_data_2d
	{
		std::vector<fvector_2d> vertex_data;
		std::vector<uint16_t> index_data;
	};

	class SIMPLE_LIBRARY_API fengine
	{
	public:
		virtual void init(float in_time);
		virtual void tick(float in_time);
		virtual void exit();
	};

	class SIMPLE_LIBRARY_API frender_engine :public fengine
	{
		typedef fengine super;

	public:
		virtual void init(float in_time);
		virtual void tick(float in_time);
		virtual void exit();

	public:
		void build_input_path(const std::wstring& in_path);
		void build_draw_object(const std::vector<fmesh_actor*>& in_objs);
		void build_camera(const fvector_3d& in_position, const fviewport_config& in_config);
	
	public:
		void strat_update(float in_time, bool breset_bone = false);
		void draw(float in_time);
		void end_update(float in_time);

	protected:
		fcamera camera;
		fviewport_config viewport_config;

		std::vector<fmesh_actor*> draw_obj;

		std::vector<frender_data_3d> frame_render_data3;
		std::wstring wpath;

		int index;
	};

	class SIMPLE_LIBRARY_API fengine_factory
	{
	public:
		template<class t>
		t* create_engine()
		{
			return new t();
		}
	};
}

